package hn.cch.spring_async_call.controller;


import hn.cch.spring_async_call.service.ApiService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.WebAsyncTask;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;


/**
 *
 */
@RequestMapping(value = "/api")
@RestController
public class ApiController {

    private Logger logger = LoggerFactory.getLogger(ApiController.class);

    @Autowired
    private ApiService apiService;

    @GetMapping(value = "/sync")
    public void sync() {
        logger.info("sync void start");
        //controller没有@Async，service使用@Async
        apiService.async();
        logger.info("sync void stop");
    }


    /**
     * 测试发现@Async只能加载control层
     * 使用Future<T>返回异步调用结果
     * 单次执行异步任务得到返回结果
     *
     * @return
     */
    @GetMapping(value = "/sync_one")
    public String sync_one() {
        logger.info("sync one start");

        // 单次执行异步任务
        //controller没有@Async，service使用@Async
        Future<String> future = apiService.async("sync_one");

        String result = "null one";
        try {
            // 阻塞等待执行结果
            result = (String) future.get();
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        logger.info("sync one stop");
        return result;
    }

    /**
     * 测试发现@Async只能加载control层
     * 使用Future<T>返回异步调用结果
     * 批量执行异步任务得到返回结果
     *
     * @param num
     * @return
     */
    @GetMapping(value = "/sync_num")
    public List<String> sync_num(@RequestParam Integer num) {
        logger.info("sync num start");
        logger.info("num:{}", num);

        // 批量执行异步任务
        List<Future> futureList = new ArrayList<>();
        CountDownLatch countDownLatch = new CountDownLatch(num);
        for (int i = 0; i < num; i++) {
            //controller没有@Async，service使用@Async
            Future<String> future = apiService.async("async:" + i, countDownLatch);
            futureList.add(future);
        }
        logger.info("async");
        List<String> resultList = new ArrayList<>();
        try {
            //等待线程池的等待队列中的任务执行完成后获取所有结果
            countDownLatch.await();
            logger.info("await");
            for (Future future : futureList) {
                // 阻塞等待执行结果
                String result = (String) future.get();
                resultList.add(result);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        logger.info("sync num stop");
        return resultList;
    }


    /**
     * 适用场景：触发后台处理数据
     */
    @Async
    @GetMapping(value = "/async")
    public void async() {
        logger.info("async void start");
        //controller使用@Async，service没有@Async
        apiService.sync();
        logger.info("async void stop");

    }


    /**
     * 测试发现@Async只能加载control层
     * 使用Future<T>返回异步调用结果
     * 经过测试这种使用场景得不到返回结果
     * @param param
     * @return
     */
    @Async
    @GetMapping(value = "/{param}/async")
    public Future<String> async(@PathVariable String param) {
        logger.info("async param start");
        logger.info("param:{}", param);
        //controller使用@Async，service没有@Async
        Future<String> future = apiService.sync(param);

        try {
            // 阻塞线程等待结果
            String result = future.get();
            logger.info("result:{}", result);
            logger.info("done={}", future.isDone());
            logger.info("Cancelled={}", future.isCancelled());
            logger.info("async param stop");
            return future;
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new AsyncResult<>(e.getMessage());
        }

    }

}
